home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 November: Tool Chest / Dev.CD Nov 98 TC.toast / Sample Code / QuickTime / JPEG Sample / JPEG.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-03-05  |  17.2 KB  |  822 lines  |  [TEXT/CWIE]

  1. /*************************************************************************************
  2. #
  3. #        JPEG.c
  4. #
  5. #        This segment handles JPEG.
  6. #
  7. #        Author(s):     Michael Marinkovich & Guillermo Ortiz
  8. #                    marink@apple.com
  9. #
  10. #        Modification History: 
  11. #
  12. #            4/3/96        MWM     Initial coding                     
  13. #
  14. #        Copyright © 1992-96 Apple Computer, Inc., All Rights Reserved
  15. #
  16. #
  17. #        You may incorporate this sample code into your applications without
  18. #        restriction, though the sample code has been provided "AS IS" and the
  19. #        responsibility for its operation is 100% yours.  However, what you are
  20. #        not permitted to do is to redistribute the source as "DSC Sample Code"
  21. #        after having made changes. If you're going to re-distribute the source,
  22. #        we require that you make it clear in the source that the code was
  23. #        descended from Apple Sample Code, but that you've made changes.
  24. #
  25. *************************************************************************************/
  26.  
  27. #include <Events.h>
  28. #include <ToolUtils.h>
  29. #include <Gestalt.h>
  30. #include <OSUtils.h>
  31. #include <Palettes.h>
  32.  
  33. #include "App.h"
  34. #include "Proto.h"
  35.  
  36.  
  37. // data unload buffer size
  38. #define kBufferSize            codecMinimumDataSize
  39.  
  40.  
  41. //----------------------------------------------------------------------
  42. //
  43. //    ReadJPEG - open a JPEG file with supplied FSSpec.
  44. //                    
  45. //
  46. //----------------------------------------------------------------------
  47.  
  48. OSErr ReadJPEG(FSSpec spec, CGrafPtr *newWorld)
  49. {
  50.     OSErr                        err = noErr;
  51.     ImageDescriptionHandle         desc;
  52.     GWorldPtr                    theWorld = nil;
  53.     GWorldPtr                    oldWorld;
  54.     GDHandle                    oldGD;
  55.     PixMapHandle                thePix;
  56.     ICMDataProcRecord             loadProc;
  57.     Handle                        image;
  58.     Rect                        bounds;
  59.     DLDataRec                    dataRec;
  60.     long                        fileLength;
  61.     long                        dataSize;
  62.     short                        refNum;
  63.     Ptr                            stripImage;
  64.     
  65.     GetGWorld(&oldWorld, &oldGD);
  66.     
  67.     if (newWorld != nil)
  68.     {
  69.         SetCursor(*GetCursor(watchCursor));            // set the cursor to a watch while busy
  70.             
  71.         err = FSpOpenDF(&spec, fsRdWrShPerm, &refNum);
  72.         if ( err == noErr ) 
  73.         {
  74.             desc = (ImageDescriptionHandle)NewHandle(sizeof(ImageDescription));
  75.             if (desc != nil)
  76.             {
  77.                 HLock((Handle)desc);
  78.                 err = ReadJPEGHeader(refNum, desc, &bounds);
  79.                 if (err == noErr)
  80.                 {
  81.                     image = NewHandleClear(kBufferSize);
  82.                     err = MemError();
  83.                     if (image != nil && err == noErr)
  84.                     {
  85.                         err = NewJPEGWorld(&theWorld, (*desc)->depth, bounds);
  86.                         if (theWorld != nil && err == noErr) 
  87.                         {
  88.                             err = SetFPos(refNum, fsFromStart , 0);
  89.                             if (err == noErr)
  90.                             {
  91.                                 thePix = GetGWorldPixMap(theWorld);
  92.                                 LockPixels(thePix);
  93.                                 SetGWorld(theWorld, nil);
  94.                                 
  95.                                 HLock(image);
  96.                                 
  97.                                 dataSize = kBufferSize;
  98.                                 
  99.                                 // make sure the filesize is greater than the buffersize
  100.                                 (void)GetEOF(refNum, &fileLength);
  101.                                 if (kBufferSize > fileLength)
  102.                                     dataSize = fileLength;
  103.                                     
  104.                                 err = FSRead(refNum, &dataSize, *image);
  105.                                 if (err == noErr)
  106.                                 {
  107.                                     fileLength = (*desc)->dataSize - kBufferSize;
  108.                                     if (fileLength < 0) 
  109.                                         fileLength = 0;
  110.                                         
  111.                                     dataRec.refNum = refNum;
  112.                                     dataRec.fileLength = fileLength;
  113.                                     dataRec.origPtr = *image;
  114.                                     dataRec.endPtr = *image + kBufferSize;
  115.                                     loadProc.dataProc = NewICMDataProc(DataLoadingProc);
  116.                                     loadProc.dataRefCon = (long)&dataRec;
  117.                                     
  118.                                     stripImage = StripAddress(*image);
  119.                                     
  120.                                     err = FDecompressImage(stripImage, desc, thePix, &bounds, nil, srcCopy, nil, nil, nil,
  121.                                                            codecHighQuality, anyCodec, kBufferSize, &loadProc, nil);
  122.                                                           
  123.                                     DisposeRoutineDescriptor(loadProc.dataProc);
  124.                                      
  125.                                      HUnlock(image);
  126.                                      
  127.                                     UnlockPixels(thePix);     
  128.                                     SetGWorld(oldWorld, oldGD);
  129.                                     
  130.                                     if (err == noErr)
  131.                                         *newWorld = theWorld;
  132.                                 }
  133.                                 
  134.                             }
  135.                             if (err != noErr)
  136.                                 DisposeGWorld(theWorld);
  137.                                 
  138.                         }
  139.                         DisposeHandle(image);
  140.  
  141.                     }
  142.                     
  143.                 }
  144.                 HUnlock((Handle)desc);                
  145.                 DisposeHandle((Handle)desc);
  146.                 
  147.             }
  148.             FSClose(refNum);                    // close the file
  149.     
  150.         }    
  151.         SetCursor(&qd.arrow );                // set cursor back to arrow
  152.     }
  153.     else
  154.         err = paramErr;
  155.         
  156.             
  157.     return err;
  158.  
  159. }
  160.  
  161.  
  162. //----------------------------------------------------------------------
  163. //
  164. //    ReadJPEGHeader - fill out the ImageDescription with needed info.
  165. //
  166. //
  167. //----------------------------------------------------------------------
  168.  
  169. OSErr ReadJPEGHeader(short refNum, ImageDescriptionHandle desc, Rect *bounds)
  170. {
  171.     OSErr                    err = noErr;
  172.     long                     imageSize;
  173.     short                     w = 0, h = 0;
  174.     short                    skip;
  175.     UInt8                     marker;
  176.     Boolean                    isJFIF = false;
  177.     Boolean                    readingExtension = false;
  178.     
  179.     // set file position to beginning of file
  180.     err = SetFPos(refNum, fsFromStart , 0);
  181.     if (err != noErr)
  182.         return err;
  183.         
  184.     // get file length so we don't overflow
  185.     err = GetEOF(refNum, &imageSize);
  186.     if (err != noErr)
  187.         return err;
  188.     
  189.     (*desc)->dataSize = imageSize;
  190.  
  191.     while (true)        // loop forever
  192.     {
  193.         marker = FindNextMarker(refNum);
  194.         
  195.         switch (marker)
  196.         {
  197.             case kSOIMarker:
  198.                 isJFIF = true;
  199.                 break;
  200.                 
  201.             case kAPPOMarker + 0:
  202.             case kAPPOMarker + 1:
  203.             case kAPPOMarker + 2:
  204.             case kAPPOMarker + 3:
  205.             case kAPPOMarker + 4:
  206.             case kAPPOMarker + 5:
  207.             case kAPPOMarker + 6:
  208.             case kAPPOMarker + 7:
  209.             case kAPPOMarker + 8:
  210.             case kAPPOMarker + 9:
  211.             case kAPPOMarker + 10:
  212.             case kAPPOMarker + 11:
  213.             case kAPPOMarker + 12:
  214.             case kAPPOMarker + 13:
  215.             case kAPPOMarker + 14:
  216.             case kAPPOMarker + 15:
  217.                 err = HandleAPPOMarker(marker, refNum, desc, &readingExtension);
  218.                 if (err != noErr)
  219.                     return err;
  220.                 break;
  221.                 
  222.             case kCommentMarker:
  223.                 SkipLength(refNum);
  224.                 break;
  225.         
  226.             case kSOFMarker + 0:        // start of frame header marker
  227.             case kSOFMarker + 1:
  228.             case kSOFMarker + 2:
  229.             case kSOFMarker + 3:
  230.             case kSOFMarker + 5:
  231.             case kSOFMarker + 6:
  232.             case kSOFMarker + 7:
  233.             case kSOFMarker + 9:
  234.             case kSOFMarker + 10:
  235.             case kSOFMarker + 11:
  236.             case kSOFMarker + 13:
  237.             case kSOFMarker + 14:
  238.             case kSOFMarker + 15:
  239.                 err = HandleSOFMarker(refNum, desc, readingExtension);
  240.                 if (err != noErr)
  241.                     return err;
  242.                     
  243.                 if (!readingExtension)
  244.                 {
  245.                     SetRect(bounds, 0, 0, (*desc)->width, (*desc)->height);
  246.  
  247.                     return noErr;
  248.                 }
  249.                 break;
  250.                 
  251.             case kDACMarker:
  252.                 skip = ReadWord(refNum) - 2;
  253.                 skip *= ReadWord(refNum);
  254.                 err = SetFPos(refNum, fsFromMark, skip);
  255.                 break;
  256.                 
  257.             case kSOSMarker:
  258.                 HandleSOSMarker(refNum);
  259.                 break;
  260.                 
  261.             case kDHTMarker:
  262.             case kDQTMarker:
  263.             case kRSTOMarker:
  264.                 SkipLength(refNum);
  265.                 break;
  266.                 
  267.             case kEOIMarker:        // we reached the end of image
  268.                 // we are reading an extension so keep going
  269.                 if (readingExtension == true)
  270.                     readingExtension = false;
  271.                 
  272.                 break;
  273.         }
  274.                 
  275.     }
  276.     
  277.     return err;
  278.     
  279. }
  280.  
  281.  
  282. //----------------------------------------------------------------------
  283. //
  284. //    FindNextMarker  -
  285. //
  286. //
  287. //----------------------------------------------------------------------
  288.  
  289. UInt8 FindNextMarker(long refNum)
  290. {
  291.      UInt8             marker;
  292.     
  293.     marker = ReadByte(refNum);
  294.     
  295.     while (marker == kStartMarker)
  296.         marker = ReadByte(refNum);
  297.  
  298.     while (marker == 0x00)
  299.     {
  300.         marker = ReadByte(refNum);
  301.  
  302.         while (marker != kStartMarker)
  303.             marker = ReadByte(refNum);
  304.             
  305.         marker = ReadByte(refNum);
  306.     }
  307.         
  308.     return marker;
  309.     
  310. }
  311.  
  312.  
  313. //----------------------------------------------------------------------
  314. //
  315. //    HandleAPPOMarker  -
  316. //
  317. //
  318. //----------------------------------------------------------------------
  319.  
  320. OSErr HandleAPPOMarker(UInt8 marker, long refNum, ImageDescriptionHandle desc, Boolean *readingExtension)
  321. {
  322.     OSErr            err = noErr;
  323.     Fixed            xRes,yRes;
  324.     long             length;
  325.     short             w = 0, h = 0;
  326.     short            units;
  327.     short            version;
  328.     UInt8            extension;
  329.     UInt8             JIFF[5];
  330.  
  331.  
  332.     // read skip bytes - header length - skip count
  333.     length = ReadWord(refNum) - 2;
  334.     
  335.     if (marker == kAPPOMarker && length >= 14)
  336.     {
  337.         JIFF[0] = ReadByte(refNum);
  338.         JIFF[1] = ReadByte(refNum);
  339.         JIFF[2] = ReadByte(refNum);
  340.         JIFF[3] = ReadByte(refNum);
  341.         JIFF[4] = ReadByte(refNum);
  342.         
  343.         // check if we really have the JFIF header
  344.         if ( JIFF[0] == 'J' && JIFF[1] == 'F'  && JIFF[2] == 'I'  && JIFF[3] == 'F' ) 
  345.         {
  346.               version = ReadWord(refNum);
  347.  
  348.             if ( version < 0x100 )
  349.             {    
  350.                 err = paramErr;
  351.                 return err;     // don't know this
  352.             }
  353.             else
  354.                 (*desc)->version = version;
  355.                 
  356.             units = ReadByte(refNum);
  357.             xRes = ReadWord(refNum);
  358.               yRes = ReadWord(refNum);
  359.  
  360.             switch ( units ) 
  361.             {
  362.                 case 0:            // no res, just aspect ratio
  363.                     xRes = FixMul(72L << 16, xRes << 16);
  364.                     yRes = FixMul(72L << 16, yRes << 16);
  365.                     break;
  366.                     
  367.                 case 1:            // dots per inch
  368.                     xRes = xRes << 16;
  369.                     yRes = yRes << 16;
  370.                     break;
  371.                     
  372.                 case 2:            // dots per centimeter (we convert to dpi )
  373.                     xRes = FixMul(0x28a3d, xRes << 16);
  374.                     yRes = FixMul(0x28a3d, xRes << 16);
  375.                     break;    
  376.                     
  377.                 default:
  378.                     break;
  379.             }
  380.             
  381.             (*desc)->hRes = xRes;
  382.             (*desc)->vRes = yRes;
  383.  
  384.             length -= 12;
  385.             err = SetFPos(refNum, fsFromMark, length);
  386.             
  387.         }
  388.         else
  389.         {
  390.             if ( JIFF[0] == 'J' && JIFF[1] == 'F'  && JIFF[2] == 'X'  && JIFF[3] == 'X' ) 
  391.             {
  392.                 *readingExtension = true;        // next markers are extensions (ignore)
  393.  
  394.                 extension = ReadByte(refNum);
  395.                 
  396.                 switch (extension)
  397.                 {
  398.                     case 0x10:
  399.                     case 0x11:
  400.                     case 0x13:
  401.                         break;
  402.                     
  403.                     default:
  404.                         err = paramErr;
  405.                         return err;
  406.                 }
  407.                     
  408.             }
  409.             
  410.         }
  411.             
  412.     }
  413.     else
  414.         err = SetFPos(refNum, fsFromMark, length);
  415.  
  416.     return err;
  417.     
  418. }
  419.  
  420.  
  421. //----------------------------------------------------------------------
  422. //
  423. //    HandleSOFMarker  -
  424. //
  425. //
  426. //----------------------------------------------------------------------
  427.  
  428. OSErr HandleSOFMarker(long refNum, ImageDescriptionHandle desc, Boolean readingExtension)
  429. {
  430.     OSErr            err = noErr;
  431.     short             w = 0;
  432.     short             h = 0;
  433.     short             components;
  434.     short            length;
  435.  
  436.     if (readingExtension == false)
  437.     {
  438.         length = ReadWord(refNum);
  439.         ReadByte(refNum);
  440.         h = ReadWord(refNum);
  441.         w = ReadWord(refNum);
  442.  
  443.         if (w && h)             // make sure we do have something to display
  444.         {
  445.             /* now make up the image description */
  446.             (*desc)->idSize         = sizeof(ImageDescription);
  447.             (*desc)->cType             = 'jpeg';
  448.             (*desc)->dataRefIndex     = 0;
  449.             (*desc)->revisionLevel     = 0;
  450.             (*desc)->vendor         = 0;
  451.             (*desc)->temporalQuality = 0;
  452.             (*desc)->spatialQuality = codecNormalQuality;
  453.             (*desc)->width             = w;
  454.             (*desc)->height         = h;
  455.             (*desc)->frameCount     = 1;
  456.             BlockMove("\pPhoto - JPEG",(*desc)->name,13);
  457.             (*desc)->clutID         = -1;
  458.             
  459.             components = ReadByte(refNum);
  460.             
  461.             switch (components) 
  462.             {
  463.                 case 1:        
  464.                     (*desc)->depth = 40;
  465.                     break;
  466.  
  467.                 case 3:
  468.                     (*desc)->depth = 32;
  469.                     break;
  470.  
  471.                 case 4:
  472.                     (*desc)->depth = 32;
  473.                     break;
  474.                                         
  475.                 default:
  476.                     err = paramErr;
  477.                     return err;
  478.                     break;
  479.             }
  480.             
  481.             err = SetFPos(refNum, fsFromMark, length - 8);
  482.             return noErr;
  483.             
  484.         }
  485.         
  486.     }
  487.     else
  488.     {
  489.         length = ReadWord(refNum) - 2;
  490.         err = SetFPos(refNum, fsFromMark, length);
  491.         if (err != noErr)
  492.             return err;
  493.     }
  494.     
  495.     return err;
  496. }
  497.  
  498. //----------------------------------------------------------------------
  499. //
  500. //    HandleSOSMarker  -
  501. //
  502. //
  503. //----------------------------------------------------------------------
  504.  
  505. void HandleSOSMarker(long refNum)
  506. {
  507.     short            components;
  508.     short            c;
  509.     
  510.     ReadWord(refNum);
  511.     components = ReadByte(refNum);
  512.     
  513.     for (c = 0; c < components; c++)
  514.         ReadWord(refNum);
  515.     
  516. }
  517.  
  518.  
  519. //----------------------------------------------------------------------
  520. //
  521. //    ReadByte -
  522. //
  523. //
  524. //----------------------------------------------------------------------
  525.  
  526. UInt8 ReadByte(short refNum)
  527. {
  528.     UInt8        data;
  529.     long        bytesNeeded = sizeof(char);
  530.  
  531.     (void)FSRead(refNum, &bytesNeeded, &data);
  532.     
  533.     return data;
  534.     
  535. }
  536.  
  537.  
  538. //----------------------------------------------------------------------
  539. //
  540. //    ReadWord -
  541. //
  542. //
  543. //----------------------------------------------------------------------
  544.  
  545. UInt16 ReadWord(short refNum)
  546. {
  547.     UInt16        data;
  548.     long        bytesNeeded = sizeof(UInt16);
  549.  
  550.     (void)FSRead(refNum, &bytesNeeded, &data);
  551.     
  552.     return data;
  553.     
  554. }
  555.  
  556.  
  557. //----------------------------------------------------------------------
  558. //
  559. //    SkipLength  -
  560. //
  561. //
  562. //----------------------------------------------------------------------
  563.  
  564. void SkipLength(long refNum)
  565. {
  566.     UInt16        skip;
  567.     
  568.     skip = (ReadWord(refNum) - 2);
  569.     SetFPos(refNum, fsFromMark, skip);
  570.     
  571. }
  572.  
  573.  
  574. //----------------------------------------------------------------------
  575. //
  576. //    NewJPEGWorld -
  577. //
  578. //
  579. //----------------------------------------------------------------------
  580.  
  581. OSErr NewJPEGWorld(GWorldPtr *theWorld, short depth, Rect theRect)
  582. {
  583.     OSErr            err = noErr;
  584.     GWorldPtr        oldPort;
  585.     PixMapHandle    thePix;
  586.     CTabHandle        cTab = nil;
  587.     GDHandle        oldGD;
  588.     
  589.     if (theWorld != nil)
  590.     {
  591.         GetGWorld(&oldPort,&oldGD);
  592.     
  593.         // if depth is greater than 32 then the 
  594.         // image is grayscale
  595.         if (depth > 32) 
  596.         {
  597.             cTab = GetCTable(depth);
  598.             depth = depth - 32;
  599.         }
  600.         
  601.         err = NewGWorld(theWorld, depth, &theRect, cTab, nil, 0L);    // try our heap
  602.         
  603.         if (err != noErr)
  604.             err = NewGWorld(theWorld, depth, &theRect, cTab, nil, useTempMem);    // else try temp
  605.     
  606.         if (err == noErr && theWorld != nil) 
  607.         {
  608.             thePix = GetGWorldPixMap(*theWorld);
  609.                     
  610.             if (LockPixels(thePix)) 
  611.             {
  612.                 SetGWorld(*theWorld, nil);
  613.                 EraseRect(&theRect);
  614.                 
  615.                 UnlockPixels(thePix);
  616.             }
  617.         }
  618.         
  619.         SetGWorld(oldPort, oldGD);    
  620.     }
  621.     else
  622.         err = paramErr;
  623.         
  624.     return err;
  625.     
  626. }
  627.  
  628.  
  629. //----------------------------------------------------------------------
  630. //
  631. //    DoSaveJPEG -
  632. //
  633. //
  634. //----------------------------------------------------------------------
  635.  
  636. OSErr SaveJPEG(WindowRef window)
  637. {
  638.     OSErr                        err = noErr;
  639.     StandardFileReply            reply;
  640.     ImageDescriptionHandle         desc;
  641.     Handle                        data;
  642.     Rect                        srcRect;
  643.     GWorldPtr                    theWorld;
  644.     PixMapHandle                thePix;
  645.     CTabHandle                    cTab = nil;
  646.     ICMFlushProcRecord            flushProc;
  647.     short                        refNum;
  648.     short                        depth;
  649.     Str255                         title;
  650.     DocHnd                        doc;
  651.     
  652.  
  653.     GetWTitle(window, title);
  654.     StandardPutFile("\pSave document as:", title, &reply) ;
  655.     
  656.     doc = (DocHnd)GetWRefCon(window);
  657.     
  658.     if (reply.sfGood && doc != nil)
  659.     {
  660.         desc = (ImageDescriptionHandle)NewHandle(sizeof(ImageDescription));
  661.  
  662.         theWorld = (**doc).world;
  663.         
  664.         if (theWorld != nil && desc != nil) 
  665.         {
  666.             srcRect = theWorld->portRect;
  667.             thePix = GetGWorldPixMap(theWorld);
  668.             
  669.             if (LockPixels(thePix)) 
  670.             {    
  671.                 // if less than 16-bit then get the color table
  672.                 // of our GWorld
  673.                 depth = (**thePix).pixelSize;
  674.                 if (depth < 16)
  675.                     cTab = (**thePix).pmTable;
  676.                 
  677.                 data = NewHandle(kBufferSize);
  678.                 err = MemError();
  679.                 
  680.                 if (data != nil && err == noErr) 
  681.                 {
  682.                     HLock(data);
  683.                                                                  
  684.                     if (reply.sfReplacing ) 
  685.                         err = FSpDelete(&reply.sfFile);
  686.                 
  687.                     err = FSpCreate(&reply.sfFile, 'JVWR', 'JPEG', reply.sfScript);
  688.                     
  689.                     if (err == noErr)
  690.                         err = FSpOpenDF(&reply.sfFile,fsRdWrPerm, &refNum);
  691.                         
  692.                     if (err == noErr)
  693.                         err = SetFPos(refNum, fsFromStart , 0);
  694.                         
  695.                     if (err == noErr)
  696.                     {
  697.                         flushProc.flushProc = NewICMFlushProc(DataUnloadProc);
  698.                         flushProc.flushRefCon = refNum;
  699.  
  700.                         err = FCompressImage(thePix, &srcRect, depth,
  701.                                              codecNormalQuality, 'jpeg',
  702.                                              bestCompressionCodec, cTab,
  703.                                              codecFlagWasCompressed, kBufferSize,
  704.                                              &flushProc, nil, desc, *data);
  705.                     }
  706.                         
  707.                     if (err == noErr)
  708.                         err = SetFPos(refNum, fsFromStart, (**desc).dataSize);
  709.  
  710.                     if (err == noErr)
  711.                         err = SetEOF(refNum, (**desc).dataSize);
  712.                                  
  713.                     if (err == noErr)        
  714.                         err = FSClose( refNum );
  715.                     
  716.                     HUnlock(data);
  717.                     DisposeHandle(data);
  718.                     
  719.                     DisposeRoutineDescriptor(flushProc.flushProc);
  720.                 }
  721.             
  722.             }
  723.             
  724.             UnlockPixels(thePix);
  725.         
  726.         }
  727.         
  728.         if (nil != desc)
  729.             DisposeHandle((Handle)desc);
  730.         
  731.     }
  732.     else
  733.         err = memFullErr;
  734.     
  735.     return err;
  736.     
  737. }            
  738.     
  739.     
  740.  
  741. //----------------------------------------------------------------------
  742. //
  743. //    DataUnloadProc -
  744. //
  745. //
  746. //----------------------------------------------------------------------
  747.  
  748. pascal OSErr DataUnloadProc(Ptr data, long bytesNeeded, long refCon)
  749. {
  750.     OSErr        err = noErr;
  751.     
  752.     if (data == nil)
  753.     {
  754.         // if data is nil QuickTime requests a new position in the 
  755.         // file from the current mark, offset by bytesNeeded.
  756.         err = SetFPos(refCon, fsFromMark, bytesNeeded);
  757.     }
  758.     else
  759.     {    
  760.         err = FSWrite(refCon, &bytesNeeded, data);
  761.     }
  762.     
  763.     return err;
  764.     
  765. }
  766.  
  767.  
  768. //----------------------------------------------------------------------
  769. //
  770. //    DataLoadingProc -
  771. //
  772. //
  773. //----------------------------------------------------------------------
  774.  
  775. pascal OSErr DataLoadingProc(Ptr *data, long bytesNeeded, long refCon)
  776. {
  777.     OSErr            err = noErr;
  778.     long            unusedDataLen;
  779.     long            newDataLen;
  780.     DLDataPtr        dataRec;
  781.     Ptr                newDataPtr;
  782.     
  783.     dataRec = (DLDataPtr)refCon;
  784.     
  785.     if (data == nil)
  786.     {
  787.         err = SetFPos(dataRec->refNum, fsFromMark, bytesNeeded);
  788.     }
  789.     else
  790.     {    
  791.         newDataPtr = *data;
  792.         
  793.         // if QT requests more data than is in the buffer 
  794.         // we will have to load more.
  795.         if ((newDataPtr + bytesNeeded) >= dataRec->endPtr) 
  796.         {
  797.             // move whats left up to the front of the buffer
  798.             unusedDataLen = dataRec->endPtr - newDataPtr;
  799.             BlockMove(newDataPtr,dataRec->origPtr, unusedDataLen);
  800.             
  801.             // now fill the buffer with new data...after the 
  802.             // data we moved to the front of the buffer of course.
  803.             newDataLen = kBufferSize - unusedDataLen;
  804.             
  805.             if (newDataLen > dataRec->fileLength)
  806.                 newDataLen = dataRec->fileLength;
  807.                 
  808.             newDataPtr = dataRec->origPtr + unusedDataLen;
  809.             
  810.             err = FSRead(dataRec->refNum, &newDataLen, newDataPtr);
  811.             
  812.             dataRec->fileLength -= newDataLen;
  813.  
  814.             *data = dataRec->origPtr;
  815.         }
  816.     }
  817.     
  818.  
  819.     return err;
  820.     
  821. }
  822.